module javascriptcore.Context;

private import glib.ConstructionException;
private import glib.Str;
private import gobject.ObjectG;
private import javascriptcore.Class;
private import javascriptcore.Exception;
private import javascriptcore.Value;
private import javascriptcore.VirtualMachine;
private import javascriptcore.c.functions;
public  import javascriptcore.c.types;


/**
 * JSCContext represents a JavaScript execution context, where all operations
 * take place and where the values will be associated.
 * 
 * When a new context is created, a global object is allocated and the built-in JavaScript
 * objects (Object, Function, String, Array) are populated. You can execute JavaScript in
 * the context by using jsc_context_evaluate() or jsc_context_evaluate_with_source_uri().
 * It's also possible to register custom objects in the context with jsc_context_register_class().
 */
public class Context : ObjectG
{
	/** the main Gtk struct */
	protected JSCContext* jSCContext;

	/** Get the main Gtk struct */
	public JSCContext* getContextStruct(bool transferOwnership = false)
	{
		if (transferOwnership)
			ownedRef = false;
		return jSCContext;
	}

	/** the main Gtk struct as a void* */
	protected override void* getStruct()
	{
		return cast(void*)jSCContext;
	}

	/**
	 * Sets our main struct and passes it to the parent class.
	 */
	public this (JSCContext* jSCContext, bool ownedRef = false)
	{
		this.jSCContext = jSCContext;
		super(cast(GObject*)jSCContext, ownedRef);
	}


	/** */
	public static GType getType()
	{
		return jsc_context_get_type();
	}

	/**
	 * Create a new #JSCContext. The context is created in a new #JSCVirtualMachine.
	 * Use jsc_context_new_with_virtual_machine() to create a new #JSCContext in an
	 * existing #JSCVirtualMachine.
	 *
	 * Returns: the newly created #JSCContext.
	 *
	 * Throws: ConstructionException GTK+ fails to create the object.
	 */
	public this()
	{
		auto __p = jsc_context_new();

		if(__p is null)
		{
			throw new ConstructionException("null returned by new");
		}

		this(cast(JSCContext*) __p, true);
	}

	/**
	 * Create a new #JSCContext in @virtual_machine.
	 *
	 * Params:
	 *     vm = a #JSCVirtualMachine
	 *
	 * Returns: the newly created #JSCContext.
	 *
	 * Throws: ConstructionException GTK+ fails to create the object.
	 */
	public this(VirtualMachine vm)
	{
		auto __p = jsc_context_new_with_virtual_machine((vm is null) ? null : vm.getVirtualMachineStruct());

		if(__p is null)
		{
			throw new ConstructionException("null returned by new_with_virtual_machine");
		}

		this(cast(JSCContext*) __p, true);
	}

	/**
	 * Get the #JSCContext that is currently executing a function. This should only be
	 * called within a function or method callback, otherwise %NULL will be returned.
	 *
	 * Returns: the #JSCContext that is currently executing.
	 */
	public static Context getCurrent()
	{
		auto __p = jsc_context_get_current();

		if(__p is null)
		{
			return null;
		}

		return ObjectG.getDObject!(Context)(cast(JSCContext*) __p);
	}

	/**
	 * Check the given @code in @context for syntax errors. The @line_number is the starting line number in @uri;
	 * the value is one-based so the first line is 1. @uri and @line_number are only used to fill the @exception.
	 * In case of errors @exception will be set to a new #JSCException with the details. You can pass %NULL to
	 * @exception to ignore the error details.
	 *
	 * Params:
	 *     code = a JavaScript script to check
	 *     length = length of @code, or -1 if @code is a nul-terminated string
	 *     mode = a #JSCCheckSyntaxMode
	 *     uri = the source URI
	 *     lineNumber = the starting line number
	 *     exception = return location for a #JSCException, or %NULL to ignore
	 *
	 * Returns: a #JSCCheckSyntaxResult
	 */
	public JSCCheckSyntaxResult checkSyntax(string code, ptrdiff_t length, JSCCheckSyntaxMode mode, string uri, uint lineNumber, out JException exception)
	{
		JSCException* outexception = null;

		auto __p = jsc_context_check_syntax(jSCContext, Str.toStringz(code), length, mode, Str.toStringz(uri), lineNumber, &outexception);

		exception = ObjectG.getDObject!(JException)(outexception);

		return __p;
	}

	/**
	 * Clear the uncaught exception in @context if any.
	 */
	public void clearException()
	{
		jsc_context_clear_exception(jSCContext);
	}

	/**
	 * Evaluate @code in @context.
	 *
	 * Params:
	 *     code = a JavaScript script to evaluate
	 *     length = length of @code, or -1 if @code is a nul-terminated string
	 *
	 * Returns: a #JSCValue representing the last value generated by the script.
	 */
	public Value evaluate(string code, ptrdiff_t length)
	{
		auto __p = jsc_context_evaluate(jSCContext, Str.toStringz(code), length);

		if(__p is null)
		{
			return null;
		}

		return ObjectG.getDObject!(Value)(cast(JSCValue*) __p, true);
	}

	/**
	 * Evaluate @code and create an new object where symbols defined in @code will be added as properties,
	 * instead of being added to @context global object. The new object is returned as @object parameter.
	 * Similar to how jsc_value_new_object() works, if @object_instance is not %NULL @object_class must be provided too.
	 * The @line_number is the starting line number in @uri; the value is one-based so the first line is 1.
	 * @uri and @line_number will be shown in exceptions and they don't affect the behavior of the script.
	 *
	 * Params:
	 *     code = a JavaScript script to evaluate
	 *     length = length of @code, or -1 if @code is a nul-terminated string
	 *     objectInstance = an object instance
	 *     objectClass = a #JSCClass or %NULL to use the default
	 *     uri = the source URI
	 *     lineNumber = the starting line number
	 *     object = return location for a #JSCValue.
	 *
	 * Returns: a #JSCValue representing the last value generated by the script.
	 */
	public Value evaluateInObject(string code, ptrdiff_t length, void* objectInstance, Class objectClass, string uri, uint lineNumber, out Value object)
	{
		JSCValue* outobject = null;

		auto __p = jsc_context_evaluate_in_object(jSCContext, Str.toStringz(code), length, objectInstance, (objectClass is null) ? null : objectClass.getClassStruct(), Str.toStringz(uri), lineNumber, &outobject);

		object = ObjectG.getDObject!(Value)(outobject);

		if(__p is null)
		{
			return null;
		}

		return ObjectG.getDObject!(Value)(cast(JSCValue*) __p, true);
	}

	/**
	 * Evaluate @code in @context using @uri as the source URI. The @line_number is the starting line number
	 * in @uri; the value is one-based so the first line is 1. @uri and @line_number will be shown in exceptions and
	 * they don't affect the behavior of the script.
	 *
	 * Params:
	 *     code = a JavaScript script to evaluate
	 *     length = length of @code, or -1 if @code is a nul-terminated string
	 *     uri = the source URI
	 *     lineNumber = the starting line number
	 *
	 * Returns: a #JSCValue representing the last value generated by the script.
	 */
	public Value evaluateWithSourceUri(string code, ptrdiff_t length, string uri, uint lineNumber)
	{
		auto __p = jsc_context_evaluate_with_source_uri(jSCContext, Str.toStringz(code), length, Str.toStringz(uri), lineNumber);

		if(__p is null)
		{
			return null;
		}

		return ObjectG.getDObject!(Value)(cast(JSCValue*) __p, true);
	}

	/**
	 * Get the last unhandled exception thrown in @context by API functions calls.
	 *
	 * Returns: a #JSCException or %NULL if there isn't any
	 *     unhandled exception in the #JSCContext.
	 */
	public JException getException()
	{
		auto __p = jsc_context_get_exception(jSCContext);

		if(__p is null)
		{
			return null;
		}

		return ObjectG.getDObject!(JException)(cast(JSCException*) __p);
	}

	/**
	 * Get a #JSCValue referencing the @context global object
	 *
	 * Returns: a #JSCValue
	 */
	public Value getGlobalObject()
	{
		auto __p = jsc_context_get_global_object(jSCContext);

		if(__p is null)
		{
			return null;
		}

		return ObjectG.getDObject!(Value)(cast(JSCValue*) __p, true);
	}

	/**
	 * Get a property of @context global object with @name.
	 *
	 * Params:
	 *     name = the value name
	 *
	 * Returns: a #JSCValue
	 */
	public Value getValue(string name)
	{
		auto __p = jsc_context_get_value(jSCContext, Str.toStringz(name));

		if(__p is null)
		{
			return null;
		}

		return ObjectG.getDObject!(Value)(cast(JSCValue*) __p, true);
	}

	/**
	 * Get the #JSCVirtualMachine where @context was created.
	 *
	 * Returns: the #JSCVirtualMachine where the #JSCContext was created.
	 */
	public VirtualMachine getVirtualMachine()
	{
		auto __p = jsc_context_get_virtual_machine(jSCContext);

		if(__p is null)
		{
			return null;
		}

		return ObjectG.getDObject!(VirtualMachine)(cast(JSCVirtualMachine*) __p);
	}

	/**
	 * Remove the last #JSCExceptionHandler previously pushed to @context with
	 * jsc_context_push_exception_handler().
	 */
	public void popExceptionHandler()
	{
		jsc_context_pop_exception_handler(jSCContext);
	}

	/**
	 * Push an exception handler in @context. Whenever a JavaScript exception happens in
	 * the #JSCContext, the given @handler will be called. The default #JSCExceptionHandler
	 * simply calls jsc_context_throw_exception() to throw the exception to the #JSCContext.
	 * If you don't want to catch the exception, but only get notified about it, call
	 * jsc_context_throw_exception() in @handler like the default one does.
	 * The last exception handler pushed is the only one used by the #JSCContext, use
	 * jsc_context_pop_exception_handler() to remove it and set the previous one. When @handler
	 * is removed from the context, @destroy_notify i called with @user_data as parameter.
	 *
	 * Params:
	 *     handler = a #JSCExceptionHandler
	 *     userData = user data to pass to @handler
	 *     destroyNotify = destroy notifier for @user_data
	 */
	public void pushExceptionHandler(JSCExceptionHandler handler, void* userData, GDestroyNotify destroyNotify)
	{
		jsc_context_push_exception_handler(jSCContext, handler, userData, destroyNotify);
	}

	/**
	 * Register a custom class in @context using the given @name. If the new class inherits from
	 * another #JSCClass, the parent should be passed as @parent_class, otherwise %NULL should be
	 * used. The optional @vtable parameter allows to provide a custom implementation for handling
	 * the class, for example, to handle external properties not added to the prototype.
	 * When an instance of the #JSCClass is cleared in the context, @destroy_notify is called with
	 * the instance as parameter.
	 *
	 * Params:
	 *     name = the class name
	 *     parentClass = a #JSCClass or %NULL
	 *     vtable = an optional #JSCClassVTable or %NULL
	 *     destroyNotify = a destroy notifier for class instances
	 *
	 * Returns: a #JSCClass
	 */
	public Class registerClass(string name, Class parentClass, JSCClassVTable* vtable, GDestroyNotify destroyNotify)
	{
		auto __p = jsc_context_register_class(jSCContext, Str.toStringz(name), (parentClass is null) ? null : parentClass.getClassStruct(), vtable, destroyNotify);

		if(__p is null)
		{
			return null;
		}

		return ObjectG.getDObject!(Class)(cast(JSCClass*) __p);
	}

	/**
	 * Set a property of @context global object with @name and @value.
	 *
	 * Params:
	 *     name = the value name
	 *     value = a #JSCValue
	 */
	public void setValue(string name, Value value)
	{
		jsc_context_set_value(jSCContext, Str.toStringz(name), (value is null) ? null : value.getValueStruct());
	}

	/**
	 * Throw an exception to @context using the given error message. The created #JSCException
	 * can be retrieved with jsc_context_get_exception().
	 *
	 * Params:
	 *     errorMessage = an error message
	 */
	public void throwMessage(string errorMessage)
	{
		jsc_context_throw(jSCContext, Str.toStringz(errorMessage));
	}

	/**
	 * Throw @exception to @context.
	 *
	 * Params:
	 *     exception = a #JSCException
	 */
	public void throwException(JException exception)
	{
		jsc_context_throw_exception(jSCContext, (exception is null) ? null : exception.getExceptionStruct());
	}

	/**
	 * Throw an exception to @context using the given error name and message. The created #JSCException
	 * can be retrieved with jsc_context_get_exception().
	 *
	 * Params:
	 *     errorName = the error name
	 *     errorMessage = an error message
	 */
	public void throwWithName(string errorName, string errorMessage)
	{
		jsc_context_throw_with_name(jSCContext, Str.toStringz(errorName), Str.toStringz(errorMessage));
	}
}
